package com.woniuxy.commons.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.commons.annotation.RequirePerms;
import com.woniuxy.commons.service.AuthService;
import com.woniuxy.commons.utils.JWTUtil;
import com.woniuxy.commons.utils.ResStatus;
import com.woniuxy.commons.utils.ResponseResult;
import com.woniuxy.commons.utils.TokenEnum;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * 拦截器可以拦截controller中动态资源，也会拦截静态资源（html、css、图片、视频）
 */

@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
    @Resource
    @Lazy  //延迟注入：解决循环依赖问题，在启动时不需要注入，用的时候注入
    private AuthService authService;

    // 该方法会在调用controller方法之前执行，返回true放行，返回false拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 可以在此处去校验token，实现访问所有的uri都需要先认证
//        System.out.println(request.getHeader("Authorization"));
//        if(request.getHeader("Authorization") == null){
//            goLogin(response);
//        }
        //1.获取到该请求调用的方法
        if (handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod)handler;
            Method method = handlerMethod.getMethod();
            //2.判断该方法上是否有指定的注解（权限注解：自定义）
            if (method.isAnnotationPresent(RequirePerms.class)){
                //3.如果有该注解，获取到注解中权限信息
                RequirePerms requirePerms = method.getDeclaredAnnotation(RequirePerms.class);
                String perms = requirePerms.value();
                //
                System.out.println(perms);

                //4.得到token，通过token得到当前用户信息
                //放在里面校验token是想实现只有加了RequirePerms注解的uri才需要认证，没加的不需要认证
                String token = request.getHeader("Authorization");
                if (token == null || token.equals("")){
                    // 没登录
                    goLogin(response);

                    // 结束请求
                    return false;
                }else {
                    // token不为空  校验token
                    TokenEnum result = JWTUtil.verify(token);
                    if (result != TokenEnum.TOKEN_SUCCESS){
                        // 非法、过期
                        // 作业：当token过期时，重新生成，refreshtoken重新设置过期时间，将token返回给前端
                        goLogin(response);

                        // 终止请求
                        return false;
                    }else {
                        // 合法，获取用户信息
                        String uname = JWTUtil.getUsername(token);

                        //5.通过openfeign调用认证、鉴权微服务鉴定是否有权限
                        ResponseResult<Boolean> identification = authService.identification(uname, perms);

                        //6.根据鉴定的结果返回true或者false
                        if(!identification.getData()){
                            noPerms(response);
                        }
                        return identification.getData();
                    }
                }
            }
        }
        return super.preHandle(request, response, handler);
    }

    // 没权限时返回的结果
    private void noPerms(HttpServletResponse response) throws IOException {
        response.setHeader("Content-Type","application/json;charset=utf-8");

        ResponseResult<Object> responseResult = new ResponseResult<>();
        responseResult.setStatus(ResStatus.NO_PERMS);
        responseResult.setCode(403);
        responseResult.setMsg("没权限");

        // 返回结果
        response.getWriter().write(new ObjectMapper().writeValueAsString(responseResult));
    }

    // 没登录时返回的结果
    private void goLogin(HttpServletResponse response) throws IOException {
        response.setHeader("Content-Type","application/json;charset=utf-8");

        ResponseResult<Object> responseResult = new ResponseResult<>();
        responseResult.setStatus(ResStatus.NO_LOGIN);
        responseResult.setCode(401);
        responseResult.setMsg("请登录");

        // 返回结果
        response.getWriter().write(new ObjectMapper().writeValueAsString(responseResult));
    }
}








